<template>
	<div class="upload-box">
		<el-upload
			action="#"
			:id="id"
			:class="['upload']"
			:multiple="false"
			:disabled="disabled"
			:show-file-list="false"
			:http-request="handleHttpUpload"
			:before-upload="beforeUpload"
			:on-success="uploadSuccess"
			:on-error="uploadError"
			:style="uploadStyle"
			:drag="drag"
			accept="image/jpeg,image/jpeg,image/png"
		>
			<img v-if="imageUrl" :src="imageUrl" class="upload-image" />
			<el-icon v-else class="upload-icon"><Plus /></el-icon>
			<div v-if="imageUrl" class="upload-handle" @click.stop>
				<div class="handle-icon" @click="editImg" v-if="!disabled">
					<el-icon><Edit /></el-icon>
					<span>编辑</span>
				</div>
				<div class="handle-icon" @click="imageView">
					<el-icon><ZoomIn /></el-icon>
					<span>查看</span>
				</div>
				<div class="handle-icon" @click="deleteImg" v-if="!disabled">
					<el-icon><Delete /></el-icon>
					<span>删除</span>
				</div>
			</div>
		</el-upload>
		<div class="el-upload__tip">
			<slot name="tip"></slot>
		</div>
		<el-image-viewer v-if="dialogVisible" @close="imageView" :url-list="[imageUrl]" />
	</div>
</template>

<script setup lang="ts" name="uploadImg">
import { ref } from "vue";
import { ElNotification } from "element-plus";
import { Plus } from "@element-plus/icons-vue";
import { uploadImg } from "@/api/modules/upload";
import type { UploadProps, UploadRequestOptions } from "element-plus";

interface UploadFileProps {
	imageUrl: string; // 图片地址 ==> 必传
	id?: string; // 组件id ==> 非必传，当页面存在多个上传组件时必传（默认为upload）
	drag?: boolean; // 是否支持拖拽上传 ==> 非必传（默认为true）
	disabled?: boolean; // 是否禁用上传组件 ==> 非必传（默认为false）
	fileSize?: number; // 单个文件大小限制 ==> 非必传（默认为 5M）
	uploadStyle?: { [key: string]: any }; // 上传组件样式 ==> 非必传
}
// 接受父组件参数
const props = withDefaults(defineProps<UploadFileProps>(), {
	id: "upload",
	drag: true,
	disabled: false,
	fileSize: 5,
	uploadStyle: () => ({ width: "175px", height: "175px" })
});

/**
 * @description 图片上传
 * @param options 上传的文件
 * */
interface UploadEmits {
	(e: "update:imageUrl", value: string): void;
	(e: "check-validate"): void;
}
const emit = defineEmits<UploadEmits>();
const handleHttpUpload = async (options: UploadRequestOptions) => {
	let formData = new FormData();
	formData.append("file", options.file);
	try {
		const { data } = await uploadImg(formData);
		emit("update:imageUrl", data!.fileUrl);
		emit("check-validate");
	} catch (error) {
		options.onError(error as any);
	}
};

/**
 * @description 删除图片
 * */
const deleteImg = () => {
	emit("update:imageUrl", "");
};

/**
 * @description 编辑图片
 * */
const editImg = () => {
	const dom = document.querySelector(`#${props.id} .el-upload__input`);
	dom!.dispatchEvent(new MouseEvent("click"));
};

/**
 * @description 文件上传之前判断
 * @param rawFile 上传的文件
 * */
const beforeUpload: UploadProps["beforeUpload"] = rawFile => {
	const imgSize = rawFile.size / 1024 / 1024 < props.fileSize;
	const imgType = ["image/jpg", "image/jpeg", "image/png"];
	if (!imgType.includes(rawFile.type))
		ElNotification({
			title: "温馨提示",
			message: "上传图片必须是 JPG/JPEG/PNG 格式！",
			type: "warning"
		});
	if (!imgSize)
		ElNotification({
			title: "温馨提示",
			message: `上传图片大小不能超过 ${props.fileSize}MB！`,
			type: "warning"
		});
	return imgType.includes(rawFile.type) && imgSize;
};

// 图片上传成功提示
const uploadSuccess = () => {
	ElNotification({
		title: "温馨提示",
		message: "图片上传成功！",
		type: "success"
	});
};

// 图片上传错误提示
const uploadError = () => {
	ElNotification({
		title: "温馨提示",
		message: "图片上传失败，请您重新上传！",
		type: "error"
	});
};

// 查看图片
const dialogVisible = ref(false);
const imageView = () => {
	dialogVisible.value = !dialogVisible.value;
};
</script>

<style scoped lang="scss">
@import "./index.scss";
</style>
